/*  Packet sniffer using libpcap library */
#include<pcap.h> 
#include<stdio.h> 
#include<net/ethernet.h> 
#include<netinet/ip_icmp.h> //Provides declarations for icmp header 
#include<netinet/udp.h> //Provides declarations for udp header 
#include<netinet/tcp.h> //Provides declarations for tcp header 
#include<netinet/ip.h> //Provides declarations for ip header   

void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void process_ip_packet(unsigned char* , int);
void print_ip_header(unsigned char* , int);
void print_tcp_header(unsigned char* buffer , int size);
void print_udp_header(unsigned char* , int);
FILE *logfile;
struct sockaddr_in source,dest;
int main() {
  pcap_if_t alldevsp[100] , *device;
  pcap_t *handle; //Handle of the device that shall be sniffed
  char errbuf[100] , *devname , *devs[20];
  int count = 0 , n;
  
  //First get the list of available devices
  printf("Finding available devices ...\t");
  if(pcap_findalldevs(&alldevsp, errbuf))  {
    printf("Error finding devices : %s\n" , errbuf);
    exit(1);
  }
  printf("Done\n");
  //Print the available devices
  printf("Available Devices are :\n");
  device = alldevsp;
  while(device != NULL)  {
    //    char * tmp = devs[count];
    devs[count] = malloc(sizeof(device->name));
    *(devs[count]) = device->name;
    printf("%d. %s - %s\n", count++ , device->name , device->description);
    device = device->next;
  }
  //Ask user which device to sniff
  printf("Enter the number of the device you want to sniff : \n");
  scanf("%d" , &n);
  devname = devs[n];

  //Open the device for sniffing
  printf("Opening device for sniffing ...\t");
  handle = pcap_open_live("eth1" , 65536 , 1 , 0 , errbuf);
  if (handle == NULL) {
    fprintf(stderr, "Couldn't open device eth0 : %s\n" , errbuf);
    exit(1);
  }  
  printf("Done\n");
  logfile=fopen("log.txt","w");
  if(logfile==NULL)
    printf("Unable to create file.\n");
  //Put the device in sniff loop  
  pcap_loop(handle , -1 , process_packet , NULL);
  return 0; 
}
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{  
  int size = header->len;
  struct ether_header *ethh;
  ethh = (struct ether_header *)packet;
  //Print the ethernet header in the log file
  if(ntohs(ethh->ether_type) == ETHERTYPE_IP)  {    
    process_ip_packet(packet + sizeof *ethh , size - sizeof ethh);
    printf("%d\n" , sizeof *ethh);
    fflush(stdout);
  }  
  return 0;
}  
void process_ip_packet(unsigned char* buffer, int size) { 
  //Get the IP Header part of this packet 
  struct iphdr *iph = (struct iphdr*)buffer;
  switch (iph->protocol) //Check the Protocol and do accordingly... 
    {   case 1: 
	//ICMP Protocol    
	//PrintIcmpPacket(Buffer,Size);
	break;
    case 2:  //IGMP Protocol    
      break; 
    case 6:  //TCP Protocol   
      print_tcp_packet(buffer , size);
      break; 
    case 17: //UDP Protocol   
      print_udp_packet(buffer , size); 
      break; 
    default: //Some Other Protocol like ARP etc.  
      break;  }
}  
void print_ip_header(unsigned char* Buffer, int Size) { 
  unsigned short iphdrlen;
  struct iphdr *iph = (struct iphdr *)Buffer;
  iphdrlen =iph->ihl*4;
  memset(&source, 0, sizeof(source)); 
  source.sin_addr.s_addr = iph->saddr;  
  memset(&dest, 0, sizeof(dest));
  dest.sin_addr.s_addr = iph->daddr;   
  fprintf(logfile,"\n");
  fprintf(logfile,"IP Header\n");
  fprintf(logfile,"   |-IP Version        : %d\n",(unsigned int)iph->version); 
  fprintf(logfile,"   |-IP Header Length  : %d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4); 
  fprintf(logfile,"   |-Type Of Service   : %d\n",(unsigned int)iph->tos); 
  fprintf(logfile,"   |-IP Total Length   : %d  Bytes(Size of Packet)\n",ntohs(iph->tot_len)); 
  fprintf(logfile,"   |-Identification    : %d\n",ntohs(iph->id)); 
  //fprintf(logfile,"   |-Reserved ZERO Field   : %d\n",(unsigned int)iphdr->ip_reserved_zero); 
  //fprintf(logfile,"   |-Dont Fragment Field   : %d\n",(unsigned int)iphdr->ip_dont_fragment); 
  //fprintf(logfile,"   |-More Fragment Field   : %d\n",(unsigned int)iphdr->ip_more_fragment); 
  fprintf(logfile,"   |-TTL      : %d\n",(unsigned int)iph->ttl);
  fprintf(logfile,"   |-Protocol : %d\n",(unsigned int)iph->protocol);  
  fprintf(logfile,"   |-Checksum : %d\n",ntohs(iph->check)); 
  fprintf(logfile,"   |-Source IP        : %s\n",inet_ntoa(source.sin_addr)); 
  fprintf(logfile,"   |-Destination IP   : %s\n",inet_ntoa(dest.sin_addr));
}   
void print_tcp_packet(unsigned char* Buffer, int Size) {  
  unsigned short iphdrlen; 
  struct iphdr *iph = (struct iphdr *)Buffer;  
  iphdrlen = iph->ihl*4;
  struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen); 
  fprintf(logfile,"***********************TCP Packet*************************\n"); 
  print_ip_header(Buffer,Size); 
  fprintf(logfile,"\n");
  fprintf(logfile,"TCP Header\n");
  fprintf(logfile,"   |-Source Port      : %u\n",ntohs(tcph->source)); 
  fprintf(logfile,"   |-Destination Port : %u\n",ntohs(tcph->dest));  
  fprintf(logfile,"   |-Sequence Number    : %u\n",ntohl(tcph->seq));  
  fprintf(logfile,"   |-Acknowledge Number : %u\n",ntohl(tcph->ack_seq));
  fprintf(logfile,"   |-Header Length      : %d DWORDS or %d BYTES\n" ,(unsigned int)tcph->doff,(unsigned int)tcph->doff*4);
  //fprintf(logfile,"   |-CWR Flag : %d\n",(unsigned int)tcph->cwr);
  //fprintf(logfile,"   |-ECN Flag : %d\n",(unsigned int)tcph->ece);
  fprintf(logfile,"   |-Urgent Flag          : %d\n",(unsigned int)tcph->urg);
  fprintf(logfile,"   |-Acknowledgement Flag : %d\n",(unsigned int)tcph->ack); 
  fprintf(logfile,"   |-Push Flag            : %d\n",(unsigned int)tcph->psh); 
  fprintf(logfile,"   |-Reset Flag           : %d\n",(unsigned int)tcph->rst);
  fprintf(logfile,"   |-Synchronise Flag     : %d\n",(unsigned int)tcph->syn);
  fprintf(logfile,"   |-Finish Flag          : %d\n",(unsigned int)tcph->fin);  
  fprintf(logfile,"   |-Window         : %d\n",ntohs(tcph->window)); 
  fprintf(logfile,"   |-Checksum       : %d\n",ntohs(tcph->check));  
  fprintf(logfile,"   |-Urgent Pointer : %d\n",tcph->urg_ptr);
  fprintf(logfile,"\n");  
  fprintf(logfile,"                        DATA Dump                         ");
  fprintf(logfile,"\n");
  fprintf(logfile,"IP Header\n");
  PrintData(Buffer,iphdrlen);
  fprintf(logfile,"TCP Header\n"); 
  PrintData(Buffer+iphdrlen,tcph->doff*4); 
  fprintf(logfile,"Data Payload\n");
  PrintData(Buffer + iphdrlen + tcph->doff*4 , (Size - tcph->doff*4-iph->ihl*4) );
  fprintf(logfile,"###########################################################\n");
}  
void print_udp_packet(unsigned char *Buffer , int Size) {  
  unsigned short iphdrlen;    
  struct iphdr *iph = (struct iphdr *)Buffer;
  iphdrlen = iph->ihl*4; 
  struct udphdr *udph = (struct udphdr*)(Buffer + iphdrlen);
  fprintf(logfile,"***********************UDP Packet*************************\n");
  print_ip_header(Buffer,Size);  
  fprintf(logfile,"nUDP Header\n");
  fprintf(logfile,"   |-Source Port      : %d\n" , ntohs(udph->source));
  fprintf(logfile,"   |-Destination Port : %d\n" , ntohs(udph->dest));  
  fprintf(logfile,"   |-UDP Length       : %d\n" , ntohs(udph->len));  
  fprintf(logfile,"   |-UDP Checksum     : %d\n" , ntohs(udph->check)); 
  fprintf(logfile,"\n"); 
  fprintf(logfile,"IP Header\n");  
  PrintData(Buffer , iphdrlen);
  fprintf(logfile,"UDP Header\n"); 
  PrintData(Buffer+iphdrlen , sizeof udph);
  fprintf(logfile,"Data Payload\n");
  PrintData(Buffer + iphdrlen + sizeof udph ,( Size - sizeof udph - iph->ihl * 4 ));  
  fprintf(logfile,"###########################################################\n");
} 
void print_icmp_packet(unsigned char* Buffer , int Size) { 
  unsigned short iphdrlen; 
  struct iphdr *iph = (struct iphdr *)Buffer;  
  iphdrlen = iph->ihl*4;   
  struct icmphdr *icmph = (struct icmphdr *)(Buffer + iphdrlen);   
  fprintf(logfile,"***********************ICMP Packet*************************\n"); 
  print_ip_header(Buffer , Size);  
  fprintf(logfile,"\n"); 
  fprintf(logfile,"ICMP Header\n");
  fprintf(logfile,"   |-Type : %d",(unsigned int)(icmph->type));    
  if((unsigned int)(icmph->type) == 11) 
    fprintf(logfile,"  (TTL Expired)\n");
  else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY) 
    fprintf(logfile,"  (ICMP Echo Reply)\n"); 
  fprintf(logfile,"   |-Code : %d\n",(unsigned int)(icmph->code)); 
  fprintf(logfile,"   |-Checksum : %d\n",ntohs(icmph->checksum));
  //fprintf(logfile,"   |-ID       : %d\n",ntohs(icmph->id));
  //fprintf(logfile,"   |-Sequence : %d\n",ntohs(icmph->sequence));
  fprintf(logfile,"\n");
  fprintf(logfile,"IP Header\n"); 
  PrintData(Buffer,iphdrlen); 
  fprintf(logfile,"UDP Header\n"); 
  PrintData(Buffer + iphdrlen , sizeof icmph);    
  fprintf(logfile,"Data Payload\n");  
  PrintData(Buffer + iphdrlen + sizeof icmph , (Size - sizeof icmph - iph->ihl * 4));   
  fprintf(logfile,"###########################################################\n");
}  
void PrintData (unsigned char* data , int Size) {  
  int i,j;
  for(i=0 ; i < Size ; i++)  {  
    if( i!=0 && i%16==0)  
      //if one line of hex printing is complete...  
      {    
	fprintf(logfile,"         ");  
	for(j=i-16 ; j<i ; j++)    {    
	  if(data[j]>=32 && data[j]<=128)   
	    fprintf(logfile,"%c",(unsigned char)data[j]);
	  //if its a number or alphabet       
	  else 
	    fprintf(logfile,"."); 
	  //otherwise print a dot  
	}   
	fprintf(logfile,"\n");  
      }   
    if(i%16==0) 
      fprintf(logfile,"   ");  
    fprintf(logfile," %02X",(unsigned int)data[i]);
    if( i==Size-1) 
      //print the last spaces   
      {    
	for(j=0;j<15-i%16;j++) fprintf(logfile,"   "); 
	//extra spaces     
	fprintf(logfile,"         ");
	for(j=i-i%16 ; j<=i ; j++)    { 
	  if(data[j]>=32 && data[j]<=128) 
	    fprintf(logfile,"%c",(unsigned char)data[j]);     
	  else fprintf(logfile,".");
	}  
	fprintf(logfile,"\n");
      } 
  }
}
